﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace iHouse.Common.Helper
{
    public class FilterToSQLBuilder
    {
        const string ParameterFormat = "@{0}";
        int StartParamIndex = 0;
        string operatorPart = string.Empty;
        private static FilterToSQLBuilder _instance = new FilterToSQLBuilder();

        public static FilterToSQLBuilder Current
        {
            get
            {
                return _instance;
            }
        }

        public string GenerateSQL(Dictionary<string, object> filterCollection, string sqlOperator, ref List<object> filterValues)
        {
            StringBuilder result = new StringBuilder();
            List<object> searchValues = new List<object>();

            foreach (KeyValuePair<string, object> pair in filterCollection)
            {
                BaseFilter filter = CreateFilter(pair, searchValues);
                if (filter != null)
                {
                    string sql = filter.Process();

                    operatorPart = (result.ToString() == string.Empty) ? string.Empty : string.Format(" {0} ", sqlOperator);
                    result.Append(operatorPart);
                    result.Append(sql);
                }
            }

            filterValues = searchValues;
            return result.ToString();
        }

        private BaseFilter CreateFilter(KeyValuePair<string, object> item, List<object> collection)
        {
            if (item.Value.GetType() == typeof(string))
            {
                return new StringFilter(item.Key, item.Value.ToString());
            }
            else if (item.Value.GetType() == typeof(int))
            {
                collection.Add(item.Value);
                return new IntFilter(item.Key, string.Format(ParameterFormat, StartParamIndex++));
            }

            return null;
        }
    }

    internal class StringFilter : BaseFilter
    {
        internal string Value { get; private set; }

        internal string Field { get; private set; }

        public StringFilter(string field, string value)
        {
            Field = field;
            Value = value;
        }

        public override string Process()
        {
            return string.Format("{0}.Contains(\"{1}\")", Field, Value);
        }
    }

    internal class IntFilter : BaseFilter
    {
        internal string Parameter { get; private set; }

        internal string Field { get; private set; }

        public IntFilter(string field, string parameter)
        {
            Field = field;
            Parameter = parameter;
        }

        public override string Process()
        {
            return string.Format("{0} = {1}", Field, Parameter);
        }
    }

    internal abstract class BaseFilter
    {
        public abstract string Process();
    }
}
